from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.model_selection import RandomizedSearchCV
import numpy as np
from scipy.stats import randint,uniform,loguniform
from sklearn.pipeline import Pipeline
from sklearn.decomposition import PCA
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler


class BuildClassifier:
    def RF(features:np.ndarray,labels:np.ndarray):
        param_dist = {
            'n_estimators': range(50, 500, 50),
            'min_samples_split': [2, 5, 10],
            'max_leaf_nodes': range(10, 100, 10),
            "max_depth": randint(3, 10)
        }
        random_search = RandomizedSearchCV(RandomForestClassifier(), param_dist, n_iter=50, cv=5, n_jobs = -1)
        random_search.fit(features, labels)
        return random_search.best_estimator_
    
    def SVM(features:np.ndarray,labels:np.ndarray,kernel:str="rbf"):
        # "linear","rbf","poly"
        param_dist = {
            "kernel": [kernel],
            'C': uniform(0.1, 10),
            'gamma': loguniform(1e-4, 1)
        }
        random_search = RandomizedSearchCV(SVC(), param_dist, n_iter=50, cv=5, n_jobs = -1)
        random_search.fit(features, labels)
        return random_search.best_estimator_
    
    def PCAKNN(features:np.ndarray,labels:np.ndarray):
        pipeline = Pipeline([
            ('scaler', StandardScaler()),
            ('pca', PCA(n_components=0.95)),
            ('knn', KNeighborsClassifier(n_neighbors=5, metric='euclidean'))
        ])

        param_dist = {
            'pca__n_components': [0.8, 0.95, 5, 10],        # 方差保留比例或固定维度
            'knn__n_neighbors': randint(1, 30),             # 邻居数范围1-30
            'knn__weights': ['uniform', 'distance'],       # 权重策略
            'knn__metric': ['euclidean', 'manhattan'],      # 距离度量方式
            'knn__leaf_size': randint(20, 50)              # KD-Tree/Ball-Tree的叶子节点大小
        }
        random_search = RandomizedSearchCV(
            estimator=pipeline,
            param_distributions=param_dist,
            n_iter=50,           # 随机采样100组参数组合
            cv=5,                 # 5折交叉验证
            n_jobs=10,            # 并行计算加速
        )
        random_search.fit(features,labels)
        return random_search.best_estimator_

    def PCAKRF(features:np.ndarray,labels:np.ndarray):
        pipeline = Pipeline([
            ('scaler', StandardScaler()),
            ('pca', PCA(n_components=0.95)),
            ('rf', RandomForestClassifier())
        ])

        param_dist = {
            'pca__n_components': [0.8, 0.95, 5, 10],        # 方差保留比例或固定维度
            'rf__n_estimators': range(50, 500, 50),
            'rf__min_samples_split': [2, 5, 10],
            'rf__max_leaf_nodes': range(10, 100, 10),
            "rf__max_depth": randint(3, 10)

        }
        random_search = RandomizedSearchCV(
            estimator=pipeline,
            param_distributions=param_dist,
            n_iter=50,           # 随机采样100组参数组合
            cv=5,                 # 5折交叉验证
            n_jobs=10,            # 并行计算加速
        )
        random_search.fit(features,labels)
        return random_search.best_estimator_
    
